#ifndef ENTERAGEN_CUH
#define ENTERAGEN_CUH

/****************** Representacion entera ********************/

/******************* Declaracion de Funciones del Host *************************/
void representacionEnteraGen();
void traerImprimirEnteraGen(float* fitnessHost, float* fitnessDevice, int tamVectorFitnessFloat, int* poblacionHost, int* poblacionDevice, int tamVectorPoblacion, int iteracion);
void traerImprimirMejorIndividuoEnteraGen(float* mejorFitnessIndividuoGPU, float* mejorFitnessIndividuoGPUDevice, int tamVectorFitnessMejoresIndividuosGPU, int* mejorIndividuoGPU, int* mejorIndividuoGPUDevice, int tamVectorMejoresIndividuosGPU, int iteracion);

/******************* Declaracion de Funciones Global del Device ********************/
__global__ void inicializarPoblacionEnteraGen(int* poblacion, float* fitnessActualDevice, struct Random randomGPU, int cantCromosomasPoblacion, float * fitnessOrdenadoDevice, unsigned long * numerosAleatoriosInicializacion);
__global__ void mainKernelEnteraGen(int* poblacionActualDevice, int* nuevaPoblacionDevice, float* fitnessActualDevice, float* nuevoFitnessDevice,  int* poblacionActualAcambiarDevice, int*  nuevaPoblacionAcambiarDevice, int* individuosAMigrarDevice, float* probabilidadRuletaDevice, float* fitnessTotalParaRuletaDevice, struct Random r, int * individuoAMigrarGPUaCPUdevice, float* fitnessOrdenadoDevice, int* vectorIndicesFitnessOrdenado, unsigned long* numerosAleatoriosSeleccion, unsigned long* numerosAleatoriosCruzamiento, unsigned long* numerosAleatoriosMutacion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosProbabilidadMutacion);
__global__ void asignarFitnessEnteraGen(int* poblacion, float* vectorFitness, float* fitnessOrdenadoDevice);

//Estas funciones son global porque es necesario sincronizar los bloques de cada poblacion antes de operar
__global__ void asignarProbabilidadRuletaEnteraGen(float* fitnessActualDevice, float* probabilidadRuletaEntera, float* fitnessTotalParaRuletaDevice, struct Random randomGPU);
__global__ void obtenerMejoresIndividuosEnteraGen(int* poblacion, float* fitness, int* mejorIndividuoDevice, float* mejorFitnessIndividuoGPUDevice);

__global__ void migracionRepresentacionEnteraGen(int* poblacionActualDevice, float* fitnessActualDevice, int* individuosAMigrarDevice, struct Random randomGPU, int* individuoAMigrarCPUaGPUdevice);
__global__ void individosAMigrarRepresentacionEnteraGen(float* nuevoFitnessDevice, int* nuevaPoblacionDevice, int* individuosAMigrarDevice, int * individuoAMigrarGPUaCPUdevice);

//__global__ void reemplazoEnteraGen(int* poblacionActualDevice, int* nuevaPoblacionDevice, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActualDevice, float* nuevoFitnessDevice);
__global__ void reemplazoElitistaSeleccionIndividuosEnteraGen(int* poblacionActual, int* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int * posIndAreemplazarViejosElitistaGPU, int * posIndAreemplazarNuevosElitistaGPU);
__global__ void reemplazoEnteraGen(int * poblacionActualDevice, int * nuevaPoblacionDevice, int * posIndAreemplazarViejosElitistaGPU, int * posIndAreemplazarNuevosElitistaGPU);

/******************* Declaracion de Funciones internas del Device *****************/
__device__ int obtenerMejorIndividuoEnteraGen(float* vectorFitness);
__device__ void obtenerPeorIndividuoEnteraGen(float* vectorFitness, int indices[2]);

__device__ int seleccionEnteraGen(float* vectorFitness, float* probabilidadRuletaDevice, struct Random randomGPU, int ejecutarFuncion, int* vectorIndicesFitnessOrdenado, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);
__device__ int seleccionPorTorneoEnteraGen(float* vectorFitness, struct Random randomGPU, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);
__device__ int seleccionPorRangoEnteraGen(int* vectorIndicesFitnessOrdenado, struct Random randomGPU, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);
__device__ int seleccionRuedaRuletaEnteraGen(float* probabilidadRuletaDevice, struct Random randomGPU, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo);

__device__ void cruzamientoRepresentacionEnteraGen(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, int ejecutarFuncion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);
__device__ void cruzamientoCromosoma1PuntoGen(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);
__device__ void cruzamientoCromosoma2PuntosGen(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento);
__device__ void cruzamientoCromosomaUniformeGen(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, struct Random randomGPU, unsigned long* numerosAleatoriosProbabilidadCruzamiento);

__device__ void mutacionEnteraGen(int* poblacion, float probabilidad, struct Random randomGPU, int ejecutarFuncion, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion);
__device__ void mutacionReajusteAleatorioGen(int* poblacion, float probabilidad, struct Random randomGPU, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion);
__device__ void mutacionPorDeslizamientoGen(int* poblacion, float probabilidad, struct Random randomGPU, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion);

//__device__ void reemplazoElitistaEnteraGen(int* poblacionActual, int* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness);
__device__ void reemplazoElitistaEnteraGen(int* poblacionActual, int* nuevaPoblacion, int* arrayParaReemplazoViejo, int* arrayParaReemplazoNuevo);

#endif

